package com.jari.lg.service.analysis.detector;

import com.jari.lg.domain.*;
import com.jari.lg.mapper.*;
import com.jari.lg.utils.BaseData;
import org.apache.tomcat.jni.Local;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.lang.Math;
import java.time.LocalDate;

@Service
public class DetectorService {

    @Autowired
    private DetectorHisResultRtMapper detectorHisMapper;

    @Autowired
    private DetectorHis5minMapper detectorHis5minMapper;

    @Autowired
    private DetectorHisHourMapper detectorHisHourMapper;

    @Autowired
    private DetectorDayMapper detectorDayMapper;

    @Autowired
    private DetectorMonthMapper detectorMonthMapper;

    private DateTimeFormatter hourFormatterWithoutSep = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
    private int interval = 5;  // 数据上传间隔5分钟
    private double vehLen = 5;  // 车辆平均长度5米
    private int lanes = 2; // 视频检测器检测的车道数
    private double speed = 30;  // 车辆通过检测器的平均速度，km/h
    private int cycle = 90;  // 交叉口信号控制周期，秒
    private double split = 0.3; // 检测器所属相位的绿信比
    private double monitorLen = 150;  // 检测器检测区域的长度，米

    public static double createDataInRange(double upperBound, double lowerBound) {
        if (upperBound == lowerBound) {
            return lowerBound;
        } else if (upperBound < lowerBound) {
            return lowerBound;
        } else {
            return Math.random()*(upperBound - lowerBound) + lowerBound;
        }
    }

    public static double round(double val, int num) {
        double temp = Math.pow(10.0, num);
        double result = Math.round(val * temp) / temp;
        return result;
    }

    /**
     * 根据数据个数、流量上下限生成检测数据
     * @param dataNum 生成数据个数
     * @param volLower 流量下限
     * @param volUpper 流量上限
     * @param interval 数据采样间隔，分钟
     * @param lanes 车道数
     * @param vehLen 车辆平均长度，米
     * @param split 绿信比
     * @param monitorLen 检测器检测区域长度
     * @return [dataNum][7]的二维数组，列依次为0流量、1平均排队长度、2最大排队长度、3平均车头时距、4时间占有率、5空间占有率、6平均速度
     */
    public static double[][] createDetectorRawData(int dataNum, int volLower, int volUpper, int interval, int lanes, double vehLen, double split, double monitorLen) {
        double[][] resultArray = new double[dataNum][7];
        for (int ii=0; ii < dataNum; ii++) {
            int vol = (int) DetectorService.createDataInRange(volUpper, volLower);
            if (vol == 0) {
                for (int jj = 0; jj < 6; jj++)
                    resultArray[ii][jj] = 0.0;
                continue;
            }
            double speed = DetectorService.createDataInRange(40,28);
            double timeOcc = (vol * vehLen * 3.6) / (lanes * speed * interval * 60);
            timeOcc = timeOcc > 1 ? 1 : DetectorService.round(timeOcc, 3);
            double avgQueue = vol == 1 ? vehLen / interval : vehLen * vol / (lanes * interval);
            avgQueue = Math.round(avgQueue);
            double queueVol = avgQueue / vehLen;
            queueVol = queueVol < 1.0 ? 1.0 : Math.round(queueVol);
            double maxQueue = DetectorService.createDataInRange(vol / lanes, queueVol);
            maxQueue *= vehLen;
            maxQueue = Math.round(maxQueue);
            maxQueue = vol == 1 ? vehLen : maxQueue;
            double avgHeadway = vol < 2 ? 0 : DetectorService.createDataInRange(interval * 60 * split / vol, 2);
            avgHeadway = DetectorService.round(avgHeadway, 1);
            double spaceOcc = DetectorService.createDataInRange(vol * vehLen, (double) vol * vehLen / (lanes * interval));
            spaceOcc = vol == 0 ? 0 : spaceOcc / monitorLen;
            spaceOcc = spaceOcc > 1 ? 1 : DetectorService.round(spaceOcc, 2);

            resultArray[ii][0] = vol;
            resultArray[ii][1] = avgQueue;
            resultArray[ii][2] = maxQueue;
            resultArray[ii][3] = avgHeadway;
            resultArray[ii][4] = timeOcc;
            resultArray[ii][5] = spaceOcc;
            resultArray[ii][6] = speed;
        }
        return resultArray;
    }

    // 生成一段时间的检测器原始数据，从2022-03-25 9:05:00至2022-03-25 10:00:00，间隔5分钟
    public void createDetectorHisTaskResult2(LocalDateTime start, LocalDateTime last) {
        while (start.isBefore(last)){
            String jobInstanceId = hourFormatterWithoutSep.format(start);
            List<DetectorHisResultRt> resultList = new ArrayList();
            int index = 0;
            double[][] resultArray = DetectorService.createDetectorRawData(
                    BaseData.videoDetectorList.size(),
                    2,
                    50,
                    interval,
                    lanes,
                    vehLen,
                    split,
                    monitorLen
            );
            for (DevBase dev : BaseData.videoDetectorList) {
                DetectorHisResultRt result = new DetectorHisResultRt();
                result.setJobinstanceid(jobInstanceId);
                result.setUuid(UUID.randomUUID().toString());
                result.setDevicecode(dev.getDevicecode());
                result.setCrossid(dev.getCrosscode());
                result.setCrossname(null);
                result.setRoadid(null);
                result.setRoadid(null);
                result.setDirection(dev.getDirection());
                result.setLanecode(dev.getLanecodes());

                result.setVolume((int) resultArray[index][0]);
                result.setAvgqueue(resultArray[index][1]);
                result.setMaxqueue(resultArray[index][2]);
                result.setAvgheadway(resultArray[index][3]);
                result.setTimeocc(resultArray[index][4]);
                result.setSpaceocc(resultArray[index][5]);
                result.setDatetime(start);
                resultList.add(result);
                index++;
            }
            detectorHisMapper.insertBatch(resultList);
            start = start.plusMinutes(5);
        }
    }

    // 生成一段时间的检测器5分钟数据，从2022-03-25 00:0:00至2022-03-26 00:00:00，间隔5分钟
    public void createDetectorHis5min2(LocalDateTime start, LocalDateTime last) {
        while (start.isBefore(last)){
            List<DetectorHis5min> resultList = new ArrayList();
            int index = 0;
            double[][] resultArray = DetectorService.createDetectorRawData(
                    BaseData.videoDetectorList.size(),
                    2,
                    50,
                    interval,
                    lanes,
                    vehLen,
                    split,
                    monitorLen
            );
            for (DevBase dev : BaseData.videoDetectorList) {
                DetectorHis5min result = new DetectorHis5min();
                result.setDetectorcode(dev.getDevicecode());
                result.setCtlcode(null);
                result.setJnccode(dev.getCrosscode());
                result.setJncname(null);
                result.setRoadid(null);
                result.setRoadid(null);
                int vol = (int) resultArray[index][0];
                result.setPassingcarnum(vol);
                result.setAvgqueue(resultArray[index][1]);
                result.setMaxqueue(resultArray[index][2]);
                result.setAvgspeed(resultArray[index][6]);
                double littlePercen = DetectorService.createDataInRange(1, 0.85);
                int littleCar = (int)Math.round(vol * littlePercen);
                int bigCar = vol - littleCar;
                result.setLittlecar(littleCar);
                result.setBigcar(bigCar);
                result.setStartdatetime(start);
                resultList.add(result);
                index++;
            }
            detectorHis5minMapper.insertBatch(resultList);
            start = start.plusMinutes(5);
        }
    }

    // 生成2月份的检测器小时数据，2022-02，间隔1小时
    public void createDetectorHisHour2(LocalDateTime start, LocalDateTime last) {
        while (start.isBefore(last)) {
            List<DetectorHisHour> resultList = new ArrayList();
            double[][] resultArray = DetectorService.createDetectorRawData(
                BaseData.videoDetectorList.size(),2,50,interval,lanes, vehLen, split, monitorLen);
            int ix = 0;
            for (DevBase dev: BaseData.videoDetectorList) {
                DetectorHisHour result = new DetectorHisHour();
                result.setDetectorcode(dev.getDevicecode());
                result.setCtlcode(null);
                result.setJnccode(dev.getCrosscode());
                result.setJncname(null);
                result.setRoadid(null);
                result.setRoadname(null);
                int vol = (int)resultArray[ix][0] * 12;
                double littlePercen = DetectorService.createDataInRange(1, 0.85);
                int littleCar = (int)Math.round(vol * littlePercen);
                int bigCar = vol - littleCar;
                result.setPassingcarnum(vol);
                result.setBigcar(bigCar);
                result.setLittlecar(littleCar);
                result.setAvgspeed(resultArray[ix][6]);
                result.setAvgqueue(resultArray[ix][1]);
                result.setMaxqueue(resultArray[ix][2]);
                result.setStartdatetime(start);
                resultList.add(result);
                ix++;
            }
            detectorHisHourMapper.insertBatch(resultList);
            start = start.plusHours(1);
        }
    }

    // 生成2021年全年每个月的交通流量，统计间隔1个月
    public void createDetectorMonth2(LocalDate start, LocalDate last) {
        while (start.isBefore(last)) {
            List<DetectorMonth> resultList = new ArrayList();
            for (DevBase dev: BaseData.videoDetectorList) {
                DetectorMonth result = new DetectorMonth();
                result.setDetectorcode(dev.getDevicecode());
                result.setCtlcode(null);
                result.setJnccode(dev.getCrosscode());
                result.setJncname(null);
                result.setRoadid(null);
                result.setRoadname(null);
                int vol = (int) DetectorService.createDataInRange(1200, 100);
                double littlePercen = DetectorService.createDataInRange(0.95, 0.85);
                int littleCar = (int)Math.round(vol * littlePercen);
                int bigCar = vol - littleCar;
                double speed = DetectorService.createDataInRange(50, 25);
                double avgQueue = vol==1 ? vehLen / interval : vehLen * vol / (lanes * interval * 12);
                avgQueue = Math.round(avgQueue);
                double queueVol = avgQueue / vehLen;
                queueVol = queueVol < 1.0 ? 1.0 :  Math.round(queueVol);
                double maxQueue = DetectorService.createDataInRange(vol / (lanes * 20), queueVol);
                maxQueue *= vehLen;
                maxQueue = Math.round(maxQueue);
                result.setPassingcarnum(vol*30);
                result.setBigcar(bigCar*30);
                result.setLittlecar(littleCar*30);
                result.setAvgspeed(speed);
                result.setAvgqueue(avgQueue);
                result.setMaxqueue(maxQueue);
                result.setStartdate(start);
                resultList.add(result);
            }
            detectorMonthMapper.insertBatch(resultList);
            start = start.plusMonths(1);
        }
    }

    // 生成2月份每天的检测器数据，2022-02，间隔1天
    public void createDetectorDay2(LocalDate start, LocalDate last) {
        while (start.isBefore(last)) {
            List<DetectorDay> resultList = new ArrayList();
            double[][] resultArray = DetectorService.createDetectorRawData(
                    BaseData.videoDetectorList.size(), 2, 50,interval,lanes,vehLen,split,monitorLen
            );
            int idx = 0;
            for (DevBase dev: BaseData.videoDetectorList) {
                DetectorDay result = new DetectorDay();
                result.setDetectorcode(dev.getDevicecode());
                result.setCtlcode(null);
                result.setJnccode(dev.getCrosscode());
                result.setJncname(null);
                result.setRoadid(null);
                result.setRoadname(null);
                int vol = (int)resultArray[idx][0] * 288;
                double littlePercen = DetectorService.createDataInRange(0.95, 0.85);
                int littleCar = (int)Math.round(vol * littlePercen);
                int bigCar = vol - littleCar;
                result.setPassingcarnum(vol);
                result.setBigcar(bigCar);
                result.setLittlecar(littleCar);
                result.setAvgspeed(resultArray[idx][6]);
                result.setAvgqueue(resultArray[idx][1]);
                result.setMaxqueue(resultArray[idx][2]);
                result.setStartdate(start);
                resultList.add(result);
                idx++;
            }
            detectorDayMapper.insertBatch(resultList);
            start = start.plusDays(1);
        }
    }

    // 每5分钟执行一次
    @Scheduled(cron = "0 0/5 * * * ?")
    public void createDetectorHisTaskResult() {
        String jobInstanceId = hourFormatterWithoutSep.format(LocalDateTime.now());
        List<DetectorHisResultRt> resultList = new ArrayList();
        for (DevBase dev: BaseData.videoDetectorList) {
            DetectorHisResultRt result = new DetectorHisResultRt();
            result.setJobinstanceid(jobInstanceId);
            result.setUuid(UUID.randomUUID().toString());
            result.setDevicecode(dev.getDevicecode());
            result.setCrossid(dev.getCrosscode());
            result.setCrossname(null);
            result.setRoadid(null);
            result.setRoadid(null);
            result.setDirection(dev.getDirection());
            result.setLanecode(dev.getLanecodes());
            int vol = new Random().nextInt(40);
            if (vol == 0) {
                result.setVolume(0);
                result.setAvgqueue(0.0);
                result.setMaxqueue(0.0);
                result.setAvgheadway(0.0);
                result.setTimeocc(0.0);
                result.setSpaceocc(0.0);
            } else {
                double timeOcc = (vol * vehLen * 3.6) / (lanes * speed * interval * 60);
                timeOcc = DetectorService.round(timeOcc, 2);
                double avgQueue = vol==1 ? vehLen / interval : vehLen * vol / (lanes * interval);
                avgQueue = Math.round(avgQueue);
                double queueVol = avgQueue / vehLen;
                queueVol = queueVol < 1.0 ? 1.0 :  Math.round(queueVol);
                double maxQueue = DetectorService.createDataInRange(vol / lanes, queueVol);
                maxQueue *= vehLen;
                maxQueue = Math.round(maxQueue);
                maxQueue = vol==1 ? vehLen : maxQueue;
                double avgHeadway = vol < 2 ? 0 : DetectorService.createDataInRange (interval * 60 * split / vol, 2);
                avgHeadway = DetectorService.round(avgHeadway, 1);
                double spaceOcc = DetectorService.createDataInRange(vol * vehLen, (double) vol * vehLen / (lanes * interval));
                spaceOcc = vol == 0 ? 0 : spaceOcc / monitorLen;
                spaceOcc = DetectorService.round(spaceOcc, 2);
                result.setVolume(vol);
                result.setAvgqueue(avgQueue);
                result.setMaxqueue(maxQueue);
                result.setAvgheadway(avgHeadway);
                result.setTimeocc(timeOcc);
                result.setSpaceocc(spaceOcc);
            }
            result.setDatetime(LocalDateTime.now());
            resultList.add(result);
        }
        detectorHisMapper.insertBatch(resultList);
    }

    // 每5分钟执行一次
    @Scheduled(cron = "0 0/5 * * * ?")
    public void createDetectorHis5min() {
        List<DetectorHis5min> resultList = new ArrayList();
        for (DevBase dev: BaseData.videoDetectorList) {
            DetectorHis5min result = new DetectorHis5min();
            result.setDetectorcode(dev.getDevicecode());
            result.setCtlcode(null);
            result.setJnccode(dev.getCrosscode());
            result.setJncname(null);
            result.setRoadid(null);
            result.setRoadname(null);
            int vol = new Random().nextInt(40);
            if (vol ==0) {
                result.setPassingcarnum(0);
                result.setBigcar(0);
                result.setLittlecar(0);
                result.setAvgspeed(0.0);
                result.setAvgqueue(0.0);
                result.setMaxqueue(0.0);
            } else {
                double littlePercen = DetectorService.createDataInRange(1, 0.85);
                int littleCar = (int)Math.round(vol * littlePercen);
                int bigCar = vol - littleCar;
                double speed = DetectorService.createDataInRange(50, 25);
                double avgQueue = vol==1 ? vehLen / interval : vehLen * vol / (lanes * interval);
                avgQueue = Math.round(avgQueue);
                double queueVol = avgQueue / vehLen;
                queueVol = queueVol < 1.0 ? 1.0 :  Math.round(queueVol);
                double maxQueue = DetectorService.createDataInRange(vol / lanes, queueVol);
                maxQueue *= vehLen;
                maxQueue = Math.round(maxQueue);
                maxQueue = vol==1 ? vehLen : maxQueue;

                result.setPassingcarnum(vol);
                result.setBigcar(bigCar);
                result.setLittlecar(littleCar);
                result.setAvgspeed(speed);
                result.setAvgqueue(avgQueue);
                result.setMaxqueue(maxQueue);
            }
            result.setStartdatetime(LocalDateTime.now());
            resultList.add(result);
        }
        detectorHis5minMapper.insertBatch(resultList);
    }

    // 每一小时执行一次
    @Scheduled(cron = "0 0 0/1 * * ? ")
    public void createDetectorHisHour() {
        List<DetectorHisHour> resultList = new ArrayList();
        for (DevBase dev: BaseData.videoDetectorList) {
            DetectorHisHour result = new DetectorHisHour();
            result.setDetectorcode(dev.getDevicecode());
            result.setCtlcode(null);
            result.setJnccode(dev.getCrosscode());
            result.setJncname(null);
            result.setRoadid(null);
            result.setRoadname(null);
            int vol = (int) DetectorService.createDataInRange(300, 20);
            double littlePercen = DetectorService.createDataInRange(1, 0.85);
            int littleCar = (int)Math.round(vol * littlePercen);
            int bigCar = vol - littleCar;
            double speed = DetectorService.createDataInRange(50, 25);
            double avgQueue = vol==1 ? vehLen / interval : vehLen * vol / (lanes * 60);  // 假设一分钟采集一次数据
            avgQueue = Math.round(avgQueue);
            double queueVol = avgQueue / vehLen;
            queueVol = queueVol < 1.0 ? 1.0 :  Math.round(queueVol);
            double maxQueue = DetectorService.createDataInRange(vol / (lanes * 6), queueVol);
            maxQueue *= vehLen;
            maxQueue = Math.round(maxQueue);
            result.setPassingcarnum(vol);
            result.setBigcar(bigCar);
            result.setLittlecar(littleCar);
            result.setAvgspeed(speed);
            result.setAvgqueue(avgQueue);
            result.setMaxqueue(maxQueue);
            result.setStartdatetime(LocalDateTime.now());
            resultList.add(result);
        }
        detectorHisHourMapper.insertBatch(resultList);
    }

    // 每天执行一次
    @Scheduled(cron = "0 0 0 */1 * ? ")
    public void createDetectorDay() {
        List<DetectorDay> resultList = new ArrayList();
        for (DevBase dev: BaseData.videoDetectorList) {
            DetectorDay result = new DetectorDay();
            result.setDetectorcode(dev.getDevicecode());
            result.setCtlcode(null);
            result.setJnccode(dev.getCrosscode());
            result.setJncname(null);
            result.setRoadid(null);
            result.setRoadname(null);
            int vol = (int) DetectorService.createDataInRange(1200, 100);
            double littlePercen = DetectorService.createDataInRange(0.95, 0.85);
            int littleCar = (int)Math.round(vol * littlePercen);
            int bigCar = vol - littleCar;
            double speed = DetectorService.createDataInRange(50, 25);
            double avgQueue = vol==1 ? vehLen / interval : vehLen * vol / (lanes * interval * 12);
            avgQueue = Math.round(avgQueue);
            double queueVol = avgQueue / vehLen;
            queueVol = queueVol < 1.0 ? 1.0 :  Math.round(queueVol);
            double maxQueue = DetectorService.createDataInRange(vol / (lanes * 20), queueVol);
            maxQueue *= vehLen;
            maxQueue = Math.round(maxQueue);

            result.setPassingcarnum(vol);
            result.setBigcar(bigCar);
            result.setLittlecar(littleCar);
            result.setAvgspeed(speed);
            result.setAvgqueue(avgQueue);
            result.setMaxqueue(maxQueue);
            result.setStartdate(LocalDate.now());
            resultList.add(result);
        }
        detectorDayMapper.insertBatch(resultList);
    }

    // 每月执行一次
    @Scheduled(cron = "0 0 0 1 * ?")
    public void createDetectorMonth() {
        List<DetectorMonth> resultList = new ArrayList();
        for (DevBase dev: BaseData.videoDetectorList) {
            DetectorMonth result = new DetectorMonth();
            result.setDetectorcode(dev.getDevicecode());
            result.setCtlcode(null);
            result.setJnccode(dev.getCrosscode());
            result.setJncname(null);
            result.setRoadid(null);
            result.setRoadname(null);
            int vol = (int) DetectorService.createDataInRange(1200, 100);
            double littlePercen = DetectorService.createDataInRange(0.95, 0.85);
            int littleCar = (int)Math.round(vol * littlePercen);
            int bigCar = vol - littleCar;
            double speed = DetectorService.createDataInRange(50, 25);
            double avgQueue = vol==1 ? vehLen / interval : vehLen * vol / (lanes * interval * 12);
            avgQueue = Math.round(avgQueue);
            double queueVol = avgQueue / vehLen;
            queueVol = queueVol < 1.0 ? 1.0 :  Math.round(queueVol);
            double maxQueue = DetectorService.createDataInRange(vol / (lanes * 20), queueVol);
            maxQueue *= vehLen;
            maxQueue = Math.round(maxQueue);

            result.setPassingcarnum(vol*30);
            result.setBigcar(bigCar*30);
            result.setLittlecar(littleCar*30);
            result.setAvgspeed(speed);
            result.setAvgqueue(avgQueue);
            result.setMaxqueue(maxQueue);
            result.setStartdate(LocalDate.now());
            resultList.add(result);
        }
        detectorMonthMapper.insertBatch(resultList);
    }
}
